package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.atguigu.tingshu.vo.album.TrackMediaInfoVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.vod.v20180717.VodClient;
import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest;
import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse;
import com.tencentcloudapi.vod.v20180717.models.MediaInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;
    @Autowired
    private VodConstantProperties vodConstantProperties;
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private TrackStatMapper trackStatMapper;
    @Autowired
    private VodService vodService;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    /**
     * @author gengjian
     * @date 2025/02/21 21:26:38
     * 上传声音
     */
    @Override
    public Map<String,String> uploadTrack(MultipartFile file) {
        //初始化一个上传客户端对象
        VodUploadClient client = new VodUploadClient(
                vodConstantProperties.getSecretId(),
                vodConstantProperties.getSecretKey());
        //设置媒体本地上传路径。我们自定义的工具类
        VodUploadRequest request = new VodUploadRequest();
        request.setMediaFilePath(UploadFileUtil.uploadTempPath(
                vodConstantProperties.getTempPath(),file));
        //调用上传方法，传入接入点地域及上传请求。
        try {
            VodUploadResponse response = client.upload(
                    vodConstantProperties.getRegion(), request);
            log.info("Upload FileId = {}", response.getFileId());
            //创建map结构返回封装结果
            Map<String,String> map = new HashMap<>();
            map.put("mediaFileId",response.getFileId());
            map.put("mediaUrl",response.getMediaUrl());
            return map;
        } catch (Exception e) {
            // 业务方进行异常处理
            log.error("Upload Err", e);
        }
        return Map.of();
    }

    /**
     * @author gengjian
     * @date 2025/02/22 14:12:51
     * 保存声音
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(Long userId, TrackInfoVo trackInfoVo) {
        //创建一个声音信息对象
        TrackInfo trackInfo = new TrackInfo();
        //属性拷贝
        BeanUtils.copyProperties(trackInfoVo,trackInfo);
        trackInfo.setUserId(userId);
        //通过albumId查专辑
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        //声音在专辑中的排序值，从1开始，值越小越靠前
        //我们可以联想到和专辑中的声音数一样
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount()+1);
        //保存一条声音还要在专辑声音数+1
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()+1);
        //更新专辑
        albumInfoMapper.updateById(albumInfo);
        //调用vod服务获取音频信息并封装
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        //保存声音信息
        trackInfoMapper.insert(trackInfo);
        //可以拿到声音id因为保存后回显
        Long trackId = trackInfo.getId();
        //调用方法保存声音统计信息
        saveTrackStat(trackId, SystemConstant.TRACK_STAT_PLAY);
        saveTrackStat(trackId, SystemConstant.TRACK_STAT_COLLECT);
        saveTrackStat(trackId, SystemConstant.TRACK_STAT_PRAISE);
        saveTrackStat(trackId, SystemConstant.TRACK_STAT_COMMENT);
    }

    /**
     * @author gengjian
     * @date 2025/02/22 15:44:22
     * 保存声音统计信息方法
     */
    private void saveTrackStat(Long trackId, String statType) {
        //创建声音统计信息对象
        TrackStat trackStat = new TrackStat();
        //封装类型
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        //封装随机数
        trackStat.setStatNum(new Random().nextInt(100000));
        trackStatMapper.insert(trackStat);
    }

    /**
     * @author gengjian
     * @date 2025/02/22 15:57:52
     * 分页查询声音列表
     */
    @Override
    public void findUserTrackPage(Page<TrackListVo> page, TrackInfoQuery trackInfoQuery) {
        //有动态条件又是多表我们写sql
        trackInfoMapper.selectUserTrackPage(page,trackInfoQuery);
    }

    /**
     * @author gengjian
     * @date 2025/02/23 14:11:49
     * 根据声音id删除
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long trackId) {
        //对应专辑声音数量减1
        //先查询声音信息得到专辑id
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Long albumId = trackInfo.getAlbumId();
        //先查询对应专辑再修改
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);
        //删除声音信息
        trackInfoMapper.delete(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getId,trackId));
        //删除声音统计信息
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId,trackId));
        //删除云点播的声音数据
        vodService.deleteMedia(trackInfo.getMediaFileId());
        //有个业务就是说我删除了专辑中一条声音，对应的其他声音比被删除声音排序靠后的（大的）在专辑中排序会往前移动一位
        //修改其他声音的排序
        trackInfoMapper.updateOrderNum(trackInfo.getAlbumId(),trackInfo.getOrderNum());
    }

    /**
     * @author gengjian
     * @date 2025/02/23 16:57:37
     * 修改声音信息
     */
    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        //根据trackId获取声音信息
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        //属性拷贝
        BeanUtils.copyProperties(trackInfoVo,trackInfo);
        //判断传过来的mediaFileId和查出来的是否一样，相等就是没修改音频，不相等说明替换了音频。
        if (!trackInfoVo.getMediaFileId().equals(trackInfo.getMediaFileId())){
            //不相等不仅要修改唯一标识，还要修改音频其他信息
            TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
            trackInfo.setMediaUrl(mediaInfo.getMediaUrl());
            trackInfo.setMediaDuration(mediaInfo.getDuration());
            trackInfo.setMediaType(mediaInfo.getType());
            trackInfo.setMediaSize(mediaInfo.getSize());
            //还要删除云点播中被替换的音频
            vodService.deleteMedia(trackInfo.getMediaFileId());
            //就不删除声音统计信息了，业务需要
        }
        //相等只修改了数据库的音频唯一标识，但是没修改音频其他信息
        trackInfoMapper.updateById(trackInfo);
    }

    /**
     * @author gengjian
     * @date 2025/03/03 18:45:10
     * 根据专辑id分页查询声音列表
     */
    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> page, Long albumId, Long userId) {
        //分析得出专辑分：免费 vip免费 付费 用户分：普通和vip用户 还有vip到期时间 和专辑试听集数有关
        //先根据专辑id获取所有声音列表
        IPage<AlbumTrackListVo> trackPage = trackInfoMapper.selectAlbumTrackPage(page, albumId);
        List<AlbumTrackListVo> albumTrackListVoList = trackPage.getRecords();
        //根据专辑id获取专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //先查试听集数
        Integer tracksForFree = albumInfo.getTracksForFree();
        //首先判断用户是否登录
        if (userId == null){
            //未登录，再判断专辑的类型 需要获得专辑信息
            if (albumInfo.getPayType() != SystemConstant.ALBUM_PAY_TYPE_FREE){
                //不免费则要设置付费，但是有试听
                //将结果集中order_num > tracksForFree的设置为付费
                albumTrackListVoList.stream().forEach(albumTrackListVo ->{
                    if (albumTrackListVo.getOrderNum() > tracksForFree){
                        albumTrackListVo.setIsShowPaidMark(true);
                    }
                });
            }
        }
        if (userId != null){
            //已登录,判断专辑类型
            //设置一个是否需要付费的标志位 可以提取公共代码
            boolean isNeedPay = false;
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())){
                //如果专辑是vip免费则判断用户是否是vip且是否过期
                //先远程调用获取用户信息
                Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(userId);
                Assert.notNull(userInfoVoResult,"远程调用用户信息失败");
                UserInfoVo userInfoVo = userInfoVoResult.getData();
                Assert.notNull(userInfoVo,"远程调用用户信息失败");
                if (userInfoVo.getIsVip() == 0 || (userInfoVo.getIsVip() == 1 && userInfoVo.getVipExpireTime().before(new Date()))){
                    //如果不是会员或会员到期则设置付费
                    isNeedPay = true;
                }
            }else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())){
                //专辑类型为付费
                isNeedPay = true;
            }
            //如果isNeedPay为true则要付费
            if (isNeedPay){
                //筛选出不试听需要付费的声音列表
                List<AlbumTrackListVo> trackListVoList = albumTrackListVoList.stream().filter(
                        albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree).toList();
                //筛选出声音id列表
                List<Long> trackIdList = trackListVoList.stream().map(AlbumTrackListVo::getTrackId).toList();
                //要看用户是否购买了专辑免费试听集数以后的声音 需要user_paid_album和user_paid_track两张表
                //远程调用用户微服务获取专辑和声音付费情况 封装成map结构 trackId:1 表示已购买 0 表示未购买
                Result<Map<Long,Integer>> result = userInfoFeignClient.userIsPaidTrack(trackIdList,albumId);
                Assert.notNull(result,"远程调用用户付费情况失败");
                Map<Long, Integer> resultMap = result.getData();
                Assert.notNull(resultMap,"远程调用用户付费情况失败");
                //循环遍历要付费的声音列表
                for (AlbumTrackListVo albumTrackListVo : trackListVoList) {
                    //如果声音id在map中找到且为0 没买 则付费
                    albumTrackListVo.setIsShowPaidMark(resultMap.get(albumTrackListVo.getTrackId()) == 0);
                }
            }
        }
        return trackPage;
    }
}
